package indi.h.targetcall.locks;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;

public class DataConflictLock<T> implements Lock<T>{

	private Map<T, BlockingQueue<Data>> block;
	private ReentrantLock rl;

	public DataConflictLock() {
		this.rl = new ReentrantLock();
		this.block = new HashMap<T, BlockingQueue<Data>>();
	}

	public void lock(T o) {
		final ReentrantLock r = rl;
		Data d = null;
		boolean isLock = false;
		try {
			r.lock();
			if (block.get(o) == null) {
				block.put(o, new LinkedBlockingQueue<Data>());
			} else if (block.containsKey(o)) {
				d = new Data();
				block.get(o).put(d);
				isLock = true;
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (isLock) {
				r.unlock();
				d.lock();
			} else
				r.unlock();
		}
	}

	public class Data {
		public boolean isLock = false;
		public boolean isUnLock = true;

		public synchronized void lock() {
			try {
				this.isLock = true;
				if (this.isUnLock)
					this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		public synchronized void unLock() {
			if (isLock)
				this.notifyAll();
			else
				this.isUnLock = false;
		}
	}

	public void unLock(T o) {
		final ReentrantLock r = rl;
		try {
			r.lock();
			if (block.get(o) == null) {

			} else if (block.get(o).size() == 0) {
				block.remove(o);
			} else if (block.get(o).size() > 0) {
				block.get(o).take().unLock();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			r.unlock();
		}
	}

}
